﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace 天机万年历
{
    public static class ControlPrinter
    {
        const int WM_PRINT = 0x0317;

        const int PRF_CHECKVISIBLE = 0x00000001,
        PRF_NONCLIENT = 0x00000002,
        PRF_CLIENT = 0x00000004,
        PRF_ERASEBKGND = 0x00000008,
        PRF_CHILDREN = 0x00000010;

        [DllImport("gdi32.dll", SetLastError = true, ExactSpelling = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)]
        private static extern bool BitBlt(HandleRef hDC, int x, int y, int nWidth, int nHeight,
                                         HandleRef hSrcDC, int xSrc, int ySrc, int dwRop);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        [ResourceExposure(ResourceScope.None)]
        public static extern IntPtr SendMessage(HandleRef hWnd, int msg, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll")]
        static extern bool OpenClipboard(IntPtr hWndNewOwner);
        [DllImport("user32.dll")]
        static extern bool EmptyClipboard();
        [DllImport("user32.dll")]
        static extern IntPtr SetClipboardData(uint uFormat, IntPtr hMem);
        [DllImport("user32.dll")]
        static extern bool CloseClipboard();
        [DllImport("gdi32.dll")]
        static extern IntPtr CopyEnhMetaFile(IntPtr hemfSrc, IntPtr hNULL);
        [DllImport("gdi32.dll")]
        static extern bool DeleteEnhMetaFile(IntPtr hemf);


        static public bool PutEnhMetafileOnClipboard(IntPtr hWnd, Metafile mf)
        {
            bool bResult = false;
            IntPtr hEMF, hEMF2;
            hEMF = mf.GetHenhmetafile(); // invalidates mf 
            if (!hEMF.Equals(new IntPtr(0)))
            {
                hEMF2 = CopyEnhMetaFile(hEMF, new IntPtr(0));
                if (!hEMF2.Equals(new IntPtr(0)))
                {
                    if (OpenClipboard(hWnd))
                    {
                        if (EmptyClipboard())
                        {
                            IntPtr hRes = SetClipboardData(14 /*CF_ENHMETAFILE*/, hEMF2);
                            bResult = hRes.Equals(hEMF2);
                            CloseClipboard();
                        }
                    }
                }
                DeleteEnhMetaFile(hEMF);
            }
            return bResult;
        }
        [DllImport("gdi32")]
        public static extern int GetEnhMetaFileBits(IntPtr hemf, int cbBuffer, byte[] lpbBuffer);


        static public void CopyControlToClipboard(Control control)
        {
            Graphics g1 = control.CreateGraphics();
            IntPtr hdc = g1.GetHdc();
            Metafile mf = new Metafile(hdc, new Rectangle(0, 0, control.Width, control.Height), MetafileFrameUnit.Pixel, EmfType.EmfPlusOnly);
            g1.ReleaseHdc(hdc);
            g1.Dispose();

            Graphics g2 = Graphics.FromImage(mf);
            ControlPrinter.DrawControl(control, g2);
            g2.Dispose();

            var enhMetafileHandle = mf.GetHenhmetafile();
            int bufferSize = GetEnhMetaFileBits(enhMetafileHandle, 0, null); // Get required buffer size.
            byte[] buffer = new byte[bufferSize]; // Allocate sufficient buffer
            if (GetEnhMetaFileBits(enhMetafileHandle, bufferSize, buffer) <= 0) // Get raw metafile data.
                throw new SystemException("DoTheTrick.GetEnhMetaFileBits");

            MemoryStream ms = new MemoryStream();
            ms.Write(buffer, 0, bufferSize);
            ms.Close();
            File.WriteAllBytes("F:\\aa.emf", buffer);
            DeleteEnhMetaFile(enhMetafileHandle);
            //PutEnhMetafileOnClipboard(control.Handle, mf);
        }

        public static void DrawControl(Control control, Graphics g)
        {
            if (!control.Created)
                control.CreateControl();

            IntPtr hDc = g.GetHdc();
            SendMessage(new HandleRef(control, control.Handle), WM_PRINT, (IntPtr)hDc,
                    (IntPtr)(PRF_CHILDREN | PRF_CLIENT | PRF_ERASEBKGND | PRF_NONCLIENT));
            g.ReleaseHdc(hDc);
        }

    }
}
